package com.avecsys.quotemanager.service.security;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.context.FacesContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.avecsys.quotemanager.constants.ApplicationConstants;
import com.avecsys.quotemanager.constants.ApplicationErrorCodes;
import com.avecsys.quotemanager.dao.common.EnumTransactionStatus;
import com.avecsys.quotemanager.dao.security.LoginDAO;
import com.avecsys.quotemanager.dao.user.UserMasterDAO;
import com.avecsys.quotemanager.exception.BusinessException;
import com.avecsys.quotemanager.exception.DAOException;
import com.avecsys.quotemanager.pojos.UserMasterPojo;
import com.avecsys.quotemanager.utils.TransactionStatus;

public class LoginServiceImpl implements LoginService {

	private final Log log = LogFactory.getLog(LoginServiceImpl.class);

	private LoginDAO loginDAO;

	private UserMasterDAO userMasterDAO;
	
	private CryptoService cryptoService;

	public CryptoService getCryptoService() {
		return cryptoService;
	}

	public void setCryptoService(CryptoService cryptoService) {
		this.cryptoService = cryptoService;
	}

	public UserMasterDAO getUserMasterDAO() {
		return userMasterDAO;
	}

	public void setUserMasterDAO(UserMasterDAO userMasterDAO) {
		this.userMasterDAO = userMasterDAO;
	}

	public LoginDAO getLoginDAO() {
		return loginDAO;
	}

	public void setLoginDAO(LoginDAO loginDAO) {
		this.loginDAO = loginDAO;
	}

	/**
	 * Method to authenticate the user
	 * 
	 * @param userMasterPojo
	 * @return Integer Transaction Status
	 * @throws BusinessException
	 */
	@Override
	public TransactionStatus authenticate(UserMasterPojo userMasterPojo)
			throws BusinessException {
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.READ_FAIL.ordinal());
		// Construct Criteria to fetch userMaster information by email and
		// password
		Map<String, Object> criteriaMap = new HashMap<String, Object>();
		criteriaMap.put("email", userMasterPojo.getEmail());
		
		//Hashing of password
		String password = cryptoService.encryptPassword(userMasterPojo.getPassword());
		
		criteriaMap.put("password", password);
		try {
			// Find all users matching the email address and password. Actually
			// if the criteria matches then it should return only one user
			// information
			List<UserMasterPojo> userMasterPojoList = loginDAO.findAllActiveByCriteria(userMasterPojo, criteriaMap);
			if (userMasterPojoList.size() > 0) {
				if (userMasterPojoList.size() == 1) {
					transactionStatus
							.setStatus(EnumTransactionStatus.READ_SUCCESS
									.ordinal());
					UserMasterPojo tmpUserMasterPojo = userMasterPojoList
							.get(0);
					// Allow Login only when email address is verified
					if (tmpUserMasterPojo.getEmailVerfied() != null
							&& tmpUserMasterPojo.getEmailVerfied().equals(
									Boolean.TRUE.toString())) {
						FacesContext
								.getCurrentInstance()
								.getExternalContext()
								.getSessionMap()
								.put(ApplicationConstants.SESSION_USER,
										tmpUserMasterPojo);
					} else {

						log.debug("Authentication Failure. Email Address not verified:"
								+ userMasterPojo.getEmail());
						transactionStatus
								.setStatus(EnumTransactionStatus.BUSINESS_FLOW_FAIL
										.ordinal());
						transactionStatus
								.setErrorCode(ApplicationErrorCodes.BEC_1000003);

					}
				} else {
					log.debug("Authentication Failure. More than one user are matching with the same credentials "
							+ userMasterPojo.getEmail());
					transactionStatus
							.setStatus(EnumTransactionStatus.BUSINESS_FLOW_FAIL
									.ordinal());
					transactionStatus
							.setErrorCode(ApplicationErrorCodes.BEC_1000002);
				}
			} else {
				log.debug("Authentication Failure. Invalid UserName and password"
						+ userMasterPojo.getEmail());
				transactionStatus
						.setStatus(EnumTransactionStatus.BUSINESS_FLOW_FAIL
								.ordinal());
				transactionStatus
						.setErrorCode(ApplicationErrorCodes.BEC_1000001);
			}
		} catch (DAOException e) {
			throw new BusinessException(e);
		}
		return transactionStatus;
	}
}
